package com.gm.census.service.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.gm.census.service.AskService;
import com.gm.census.service.CongregationService;
import com.gm.census.service.EntryService;
import com.gm.census.service.IndexService;
import com.gm.census.service.ServiceFactory;
import com.gm.census.service.UserService;
import com.google.appengine.api.NamespaceManager;

public class ServiceFactoryImpl implements ServiceFactory {

	public ServiceFactoryImpl(UserService usr, AskService ask,
			EntryService indications, EntryService visits, IndexService idx,
			CongregationService cng) {
		this.usr = get(usr);
		this.ask = get(ask);
		this.indications = get(indications);
		this.visits = get(visits);
		this.idx = get(idx);
		this.cng = get(cng);
	}

	private UserService usr;
	private AskService ask;
	private EntryService indications;
	private EntryService visits;
	private IndexService idx;
	private CongregationService cng;

	@SuppressWarnings({ "unchecked" })
	protected <T> T get(T obj) {
		try {
			Class<? extends Object> clazz = obj.getClass();
			return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
					clazz.getInterfaces(), new ServiceInvocationHandler(obj));
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		}
	}

	private static class ServiceInvocationHandler implements InvocationHandler {

		private static final Logger log = Logger
				.getLogger(ServiceInvocationHandler.class.getName());
		private Object o;

		public ServiceInvocationHandler(Object o) {
			this.o = o;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			if (log.isLoggable(Level.FINE))
				log.fine("before " + method.getName() + "::"
						+ NamespaceManager.get());
			Object ret = method.invoke(o, args);
			if (log.isLoggable(Level.FINE))
				log.fine("after " + method.getName() + "::"
						+ NamespaceManager.get());
			return ret;
		}
	}

	public UserService getUserService() {
		return usr;
	}

	public AskService getAskService() {
		return ask;
	}

	@Override
	public EntryService getIndicationService() {
		return indications;
	}

	@Override
	public EntryService getVisitService() {
		return visits;
	}

	@Override
	public IndexService getIndexService() {
		return idx;
	}

	@Override
	public CongregationService getCongregationService() {
		return cng;
	}
}
